package day15;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//测试单例模式
public class TestSingleton {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        User4 u1=User4.get();
        User4 u2=User4.get();
        User4 u3=User4.get();
        System.out.println(u1);
        System.out.println(u2);
        System.out.println(u3);
        //反射创建对象，哪怕你构造私有了，也可以使用
        Class c=User4.class;
        Constructor con=c.getDeclaredConstructor();
        //开启私有权限
        con.setAccessible(true);
        User4 u4=(User4) con.newInstance();
        System.out.println(u4);
    }
}
//饿汉式：无论对象是否使用我都先创建好
class User{
    //1.提供一个先创建好的静态私有属性
    private static User u=new User();
    //2.构造方法私有化
    private User(){}
    //3.提供一个公开的方法，帮你返回一个对象
    public static User get(){
        return u;
    }
}

//懒汉式：当你需要的单例对象比较大时，初始化消耗很多资源
//懒汉式可以延迟初始化，提高性能，只有第一次使用时才会初始化
class User2{
    //1.提供一个先创建好的静态私有属性
    private static User2 u=new User2();
    //2.构造方法私有化
    private User2(){}
    //3.提供一个公开的方法，帮你返回一个对象
    //bug：比较适用于竞争比较小的时候，如果竞争激烈的时候，
    //很可能有多个线程，同时进入if，就可能创建多个对象出来

//    public static User2 get(){
//        if (u==null){//第一次使用，这个时候才开始创建对象
//            u=new User2();
//        }
//        return u;
//    }

    //解决方法：添加synchronized关键字,可以实现让这个方法添加
    //同步锁，这样，无论多少个线程需要这个方法，都是排队使用
    //相当于一个一个使用，所有就不会出现并发问题，不会出现创建多个对象
    public static synchronized User2 get(){
        if (u==null){
            u=new User2();
        }
        return u;
    }
}


//双重检锁：如果需要多个线程环境下，延迟初始化对象时，它可以提供
//一种高效率线程安全的懒加载方式
class User3{
    private static User3 u;
    private User3(){}
    public static User3 get(){
        if (u==null){  //是否为空
            synchronized(User3.class){ //添加同步锁
                if (u==null){
                    u=new User3();
                }
            }
        }
        return u;
    }
}

//静态内部类方式：当需要延时初始化对象，而且还要保证线程安全
//静态内部类提供了一种比较优雅的实现方式
class User4{private static User4 u;
    //1.私有构造方法
    private User4(){}
    //2.私有静态内部类（里面复杂把对象初始化）
    //这里面负责了线程安全：由于静态内部类比较特殊，只有被调用的时候才会被加载
    //这样就实现了懒加载的方式，再由于类加载的过程在java中
    //本身就是线程安全的，不需要额外的同步机制
    private static class User4Handler{
        private static final User4 u=new User4();
    }
    //3.提供公开静态的返回一个对象的方法
    public static User4 get(){
        return User4Handler.u;
    }
}

//枚举实现
enum User5{
    ONE;
    private User5(){

    }
    public static User5 get(){
        return ONE;
    }
}